package com.limeng.server;

import com.limeng.catalina.Connector;
import com.limeng.catalina.Engine;
import com.limeng.catalina.Service;
import com.limeng.catalina.mapper.MappedHost;
import com.limeng.catalina.mapper.MappedWrapper;
import com.limeng.catalina.mapper.Mapper;
import com.limeng.server.filter.WebFileFilter;
import com.limeng.utils.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

public class BootStrap_v4 {

    private final static String DEFAULT_PORT = "8080";

    private Mapper mapper = new Mapper();

    private String host;

    private int port;

    private MiniCatClassLoader classLoader = new MiniCatClassLoader();

    public static void main(String[] args) throws Exception {

        BootStrap_v4 bootStrap = new BootStrap_v4();
        bootStrap.init();
        bootStrap.startup();
    }

    protected void startup() throws IOException {

        System.out.println("=====>>>Minicat start on port：" + port);
        ServerSocket serverSocket = new ServerSocket(port);

        int corePoolSize = 50;
        int maximumPoolSize = 100;
        long keepAliveTime = 100l;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue workQueue = new ArrayBlockingQueue(100);
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,
                keepAliveTime, unit, workQueue, handler);
        while(true){
            Socket socket = serverSocket.accept();
            MiniServerThread runnable = new MiniServerThread(socket,mapper);
            executor.execute(runnable);
        }
    }

    private void init() throws Exception {
        InputStream severInputStream = BootStrap_v4.class.getClassLoader().getResourceAsStream("server.xml");
        SAXReader severReader = new SAXReader();
        Document severDocument = severReader.read(severInputStream);
        Element severElemet = severDocument.getRootElement();
        List<Element> services = severElemet.elements("Service");
        for (Element serviceElemet: services) {
            Element connectorElement = serviceElemet.element("Connector");
            String stringPort = StringUtils.defaultString(connectorElement.attributeValue("port"),DEFAULT_PORT);
            port = Integer.parseInt(stringPort);

            Element engineElement = serviceElemet.element("Engine");
            Element hostElement = engineElement.element("Host");
            host = hostElement.attributeValue("name");
            String appBase = hostElement.attributeValue("appBase");
            Connector connector = new Connector(port);

            MappedHost mappedHost = new MappedHost(host, appBase);
            mapper.addHost(mappedHost);

            Engine engine = new Engine(mappedHost);

            Service service = new Service(connector, engine);

            File webappsFolder = new File(appBase);
            if(webappsFolder.exists() && webappsFolder.isDirectory()){
                File[] contextFiles = webappsFolder.listFiles();
                for (File contextFile: contextFiles) {
                    String contextName = contextFile.getName();
                    mapper.setContext(contextName);
                    initSingleWebApp(port, contextName,contextFile);
                }
            }
        }

        System.out.println(mapper.getWrapper("web_demo1","/demo1"));
    }

    private void initSingleWebApp(int port, String contextName,File contextFile) throws DocumentException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        WebFileFilter webConfigfilter = new WebFileFilter(contextFile.getName());
        File webInfoFolder = contextFile.listFiles(webConfigfilter)[0];
        File[] webInfoFiles = webInfoFolder.listFiles();
        File classesFolder = webInfoFiles[0];
        File webConfigFile = webInfoFiles[1];

        Map<String,File> files = new HashMap<>();
        webConfigfilter.listClasses(files, classesFolder);

        SAXReader reader = new SAXReader();
        Document document = reader.read(webConfigFile);
        Element rootElement = document.getRootElement();
        List<Element> servletNodes = rootElement.selectNodes("//servlet");
        //<servlet-name>lagouServlet</servlet-name>
        for (Element node : servletNodes) {
            Element servletNameNode = (Element)node.elements("servlet-name").get(0);
            String servletName = servletNameNode.getStringValue();
            Element servletClassNode = (Element)node.elements("servlet-class").get(0);
            String servletClassName = servletClassNode.getStringValue();
            //<url-pattern>/lagou</url-pattern>
            Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");

            String urlPattern = servletMapping.element("url-pattern").getStringValue();
            Class servletClass = classLoader.loadClass(files.get(servletClassName).getAbsolutePath());
            Servlet servlet = (Servlet) servletClass.newInstance();

            MappedWrapper wrapper = new MappedWrapper(urlPattern, servlet);
            mapper.addWrapper(contextName,urlPattern, wrapper);
        }

    }

}
